﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Core.Tools
{
    /// <summary>
    /// 集合迭代器
    /// </summary>
    /// <typeparam name="T">集合的元素类型</typeparam>
    public class CollectionEnumerable<T> : IEnumerable<T>, ICollection, ICollection<T>
    {
        private readonly Func<int, T> GetValue;
        private int End;
        private int Begin;
        private bool IsAsc;

        public int Count
        {
            get
            {
                return End - Begin + 1;
            }
        }

        public T this[int Index]
        {
            get
            {
                if (Index >= Begin && Index <= End)
                {
                    return GetValue(Index);
                }

                throw new IndexOutOfRangeException("Index");
            }
        }

        /// <summary>
        /// 指定范围初始化迭代器
        /// </summary>
        /// <param name="GetValue">获得值的函数</param>
        /// <param name="Begin">开始索引</param>
        /// <param name="End">结束索引</param>
        /// <param name="IsAsc">是否正序迭代</param>
        public CollectionEnumerable(Func<int, T> GetValue, int Begin, int End, bool IsAsc)
        {
            this.GetValue = GetValue;
            this.Begin = Begin;
            this.End = End;
            this.IsAsc = IsAsc;
        }
        /// <summary>
        /// 指定长度初始化迭代器
        /// </summary>
        /// <param name="GetValue">获得值的函数</param>
        /// <param name="Length">集合长度</param>
        /// <param name="IsAsc">是否正序迭代</param>
        public CollectionEnumerable(Func<int, T> GetValue, int Length, bool IsAsc) : this(GetValue, 0, Length - 1, IsAsc)
        {

        }
        /// <summary>
        /// 获得迭代器
        /// </summary>
        /// <returns>迭代器</returns>
        public IEnumerator<T> GetEnumerator()
        {
            return new CollectionEnumerator<T>(GetValue, Begin, End, IsAsc);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void CopyTo(Array Array, int Index)
        {
            if (Array == null)
            {
                throw new ArgumentNullException("array");
            }

            if (Index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            int Length = Array.Length - Index;

            if (Length < Count)
            {
                throw new ArgumentException("Length");
            }

            if (Array.Rank != 1)
            {
                throw new ArgumentException("Rank");
            }

            if (Array is T[])
            {
                var TypedArray = (T[])Array;
                
                foreach (var Item in this)
                {
                    TypedArray[Index] = Item;
                    ++Index;
                }
            }
            else
            {
                foreach (var Item in this)
                {
                    Array.SetValue(Item, Index);
                    ++Index;
                }
            }
        }




        object ICollection.SyncRoot
        {
            get
            {
                return null;
            }
        }

        bool ICollection.IsSynchronized
        {
            get
            {
                return false;
            }
        }

        void ICollection<T>.Add(T Item)
        {
            throw new NotSupportedException("Add");
        }

        void ICollection<T>.Clear()
        {
            throw new NotSupportedException("Clear");
        }

        bool ICollection<T>.Contains(T Item)
        {
            var Comparer = EqualityComparer<T>.Default;

            foreach (var Element in this)
            {
                if (Comparer.Equals(Element, Item))
                {
                    return true;
                }
            }

            return false;
        }

        void ICollection<T>.CopyTo(T[] Array, int ArrayIndex)
        {
            CopyTo(Array, ArrayIndex);
        }

        bool ICollection<T>.Remove(T item)
        {
            throw new NotSupportedException("Remove");
        }

        bool ICollection<T>.IsReadOnly
        {
            get
            {
                return true;
            }
        }
    }

    /// <summary>
    /// 集合迭代器
    /// </summary>
    /// <typeparam name="T">集合的元素类型</typeparam>
    public class CollectionEnumerator<T> : IEnumerator<T>
    {
        private readonly Func<int, T> GetValue;
        private int End;
        private int Begin;
        private int Index;
        private bool IsAsc;

        /// <summary>
        /// 指定范围初始化迭代器
        /// </summary>
        /// <param name="GetValue">获得值的函数</param>
        /// <param name="Begin">开始索引</param>
        /// <param name="End">结束索引</param>
        /// <param name="IsAsc">是否正序迭代</param>
        public CollectionEnumerator(Func<int, T> GetValue, int Begin, int End, bool IsAsc)
        {
            this.GetValue = GetValue;
            this.Begin = Begin;
            this.End = End;
            this.IsAsc = IsAsc;

            Reset();
        }
        /// <summary>
        /// 指定长度初始化迭代器
        /// </summary>
        /// <param name="GetValue">获得值的函数</param>
        /// <param name="Length">集合长度</param>
        /// <param name="IsAsc">是否正序迭代</param>
        public CollectionEnumerator(Func<int, T> GetValue, int Length, bool IsAsc) : this(GetValue, 0, Length - 1, IsAsc)
        {

        }
        public T Current
        {
            get
            {
                if (Index >= Begin && Index <= End)
                {
                    return GetValue(Index);
                }

                throw new IndexOutOfRangeException("Index");
            }
        }

        object IEnumerator.Current
        {
            get
            {
                return Current;
            }
        }

        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            if (IsAsc)
            {
                try
                {
                    return Index < End;
                }
                finally
                {
                    ++Index;
                }

            }
            else
            {
                try
                {
                    return Index > Begin;
                }
                finally
                {
                    --Index;
                }
            }
        }

        public void Reset()
        {
            Index = IsAsc ? Begin - 1 : End + 1;
        }
    }
}
